#include "Endian.h"

Endian::Kind kind = Endian::Kind::UNKNOWN;

extern short (*Endian::bigShort) (short s) = 0;
extern short (*Endian::littleShort) (short s) = 0;
extern int (*Endian::bigLong) (int i) = 0;
extern int (*Endian::littleLong) (int i) = 0;
extern float (*Endian::bigFloat) (float f) = 0;
extern float (*Endian::littleFloat) (float f) = 0;
extern double (*Endian::bigDouble) (double f) = 0;
extern double (*Endian::littleDouble) (double d) = 0;

void Endian::init() {
	char endianTest[2] = { 1, 0 };
	if (*(short*) endianTest == 1) {
		// little
		kind = Endian::Kind::LITTLE;
		Endian::bigShort = Endian::swapShort;
		Endian::bigLong = Endian::swapLong;
		Endian::bigFloat = Endian::swapFloat;
		Endian::bigDouble = Endian::swapDouble;
		Endian::littleShort = Endian::noSwapShort;
		Endian::littleLong = Endian::noSwapLong;
		Endian::littleFloat = Endian::noSwapFloat;
		Endian::littleDouble = Endian::noSwapDouble;
	} else {
		kind = Endian::Kind::BIG;
		Endian::littleShort = Endian::swapShort;
		Endian::littleLong = Endian::swapLong;
		Endian::littleFloat = Endian::swapFloat;
		Endian::littleDouble = Endian::swapDouble;
		Endian::bigShort = Endian::noSwapShort;
		Endian::bigLong = Endian::noSwapLong;
		Endian::bigFloat = Endian::noSwapFloat;
		Endian::bigDouble = Endian::noSwapDouble;
	}
}

Endian::Kind Endian::endian() {
	return kind;
}

short Endian::noSwapShort(short s) {
	return s;
}

int Endian::noSwapLong(int i) {
	return i;
}

float Endian::noSwapFloat(float f) {
	return f;
}

double Endian::noSwapDouble(double d) {
	return d;
}

short Endian::swapShort(short s) {
  return (s & 0xff << 8) + ((s >> 8) & 0xff);
}

int Endian::swapLong(int i) {
	return ((int)(i & 0xff) << 24) + ((int)(( i >> 8 ) & 0xff) << 16) + ((int)(( i>>16) & 0xff) << 8) + (i>>24) & 0xff;
}

float Endian::swapFloat(float f) {
	union {
		float f;
		unsigned char b[4];
	} dat1, dat2;
	dat1.f = f;
	for (auto i = 0; i < 4; i++) {
		dat2.b[i] = dat1.b[3 - i];
	}
	return dat2.f;
}

double Endian::swapDouble(double d) {
	union {
		double d;
		unsigned char b[8];
	} dat1, dat2;
	dat1.d = d;
	for (auto i = 0; i < 8; i++) {
		dat2.b[i] = dat1.b[7 - i];
	}
	return dat2.d;
}